package com.fastadmin.common.jwt;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.fastadmin.pojo.FUser;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.fastadmin.common.FAConst.LoginConst.REDIS_USER_TIME;


@Slf4j
public class JwtTokenUtil implements Serializable {
    private static final Logger logger = LoggerFactory.getLogger(JwtTokenUtil.class);
    private static final long serialVersionUID = -3301605591108950415L;
    public static final String CLAIM_KEY_USERNAME = "username";
    public static final String CLAIM_KEY_CREATED = "created";
    public static final String CLAIM_KEY_PHONE = "phone";
    public static final String CLAIM_KEY_EMAIL = "email";
    public static final String CLAIM_KEY_USER_ID = "userid";

    private static String secret = "eyJhbGciOiJIUzUxMiJ9eyJjcmVhdGVkIjoxNTY0ODI1NDI2MzAyLCJ1c2VyaWQiOjEsImVtYWlsIjoiMTMyMTM2NjI3MUBxcS5jb20iLCJ1c2VybmFtZSI6Ink3NzI4MTYzIiwiZXhwIjoxNTY1NDMwMjI2fQsYzpUUf8GeTPjROavoNLvBvxyYnCHZ3Z4anBIN4tXQk4XlhGRDd15Q2Pc7b5doJusPqDU72PCwHrox9eWVgbcbg";


    /**
     * 从token获取user
     *
     * @param token
     * @return
     */
    public static FUser getUser(String token) {
        try {
            final Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
            Long userId = claims.get(CLAIM_KEY_USER_ID, Long.class);
            String username = claims.get(CLAIM_KEY_USERNAME, String.class);
            String phone = claims.get(CLAIM_KEY_PHONE, String.class);
            Date created = new Date(claims.get(CLAIM_KEY_CREATED, Long.class));
            String email = (String) claims.get(CLAIM_KEY_EMAIL, String.class);

            FUser user = new FUser();
            user.setEmail(email);
            user.setUsername(username);
            user.setId(userId);
            user.setPhone(phone);
            return user;
        } catch (Exception e) {
            logger.error("{}", ExceptionUtil.stacktraceToString(e));
            return null;
        }
    }

    public static Long getUserIdFromToken(String token) {
        try {
            return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().get(CLAIM_KEY_USER_ID, Long.class);
        } catch (ExpiredJwtException e) {
            logger.info("JWT 认证过期了！", ExceptionUtil.stacktraceToString(e));
            return null;
        } catch (UnsupportedJwtException e) {
            logger.info("不支持 Jwt e:{}", ExceptionUtil.stacktraceToString(e));
            return null;
        } catch (MalformedJwtException e) {
            logger.info("MalformedJwtException Jwt e:{}", ExceptionUtil.stacktraceToString(e));
            return null;
        } catch (SignatureException e) {
            logger.info("SignatureException Jwt e:{}", ExceptionUtil.stacktraceToString(e));
            return null;
        } catch (IllegalArgumentException e) {
            logger.info("IllegalArgumentException Jwt e:{}", ExceptionUtil.stacktraceToString(e));
            return null;
        }
    }

    public static String getUserPhoneFromToken(String token) {
        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().get(CLAIM_KEY_PHONE, String.class);
    }

    public static Date getCreatedDateFromToken(String token) {
        return new Date(Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().get(CLAIM_KEY_CREATED, Long.class));
    }
    /**
     * 获取到期时间
     *
     * @param token
     * @return
     */


    /**
     * 是否过期
     *
     * @param token
     * @return
     */
    private static Boolean isTokenExpired(String token) {
        final Date expiration = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getExpiration();
        return expiration.before(new Date());
    }

    /**
     * @param created           token的时间
     * @param lastPasswordReset 最新重置密码的时间
     * @return
     */
    private static Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
        return (lastPasswordReset != null && created.before(lastPasswordReset));
    }

    public static String generateToken(Map<String, Object> claims) {
        return Jwts
                .builder()
                .setClaims(claims)
//                .setExpiration(new Date(System.currentTimeMillis() + 1000000))
                .signWith(SignatureAlgorithm.HS512, secret)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + REDIS_USER_TIME * 1000))
                .compact();
    }

    /**
     * 刷新token，重设时间
     *
     * @param token
     * @return
     */
    public static String refreshToken(String token) {
        String refreshedToken;
        try {
            final Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
            claims.put(CLAIM_KEY_CREATED, new Date());
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            logger.debug("{}", ExceptionUtil.stacktraceToString(e));
            refreshedToken = null;
        }
        return refreshedToken;
    }

//    /**
//     * 根据手机号验证token 是否过期
//     * @param token
//     * @param user
//     * @return
//     */
//    public Boolean validateTokenByPhone(String token, User user) {
//        final String phone = getUserPhoneFromToken(token);
//        final Date created = getCreatedDateFromToken(token);
//        return (phone.equals(user.getPhone())
//                && !isTokenExpired(token)
//                && !isCreatedBeforeLastPasswordReset(created, user.getReset_password_time()));
//    }

    /**
     * 根据 user id来验证token 是否能用
     *
     * @param token
     * @param user
     * @return
     */
    public static Boolean validateToken(String token, FUser user) {
        try {
            Long userid = getUserIdFromToken(token);
            Date created = getCreatedDateFromToken(token);
            return (userid.equals(user.getId())
                    && !isTokenExpired(token)
                    && !isCreatedBeforeLastPasswordReset(created, user.getReset_password_time()));
        } catch (ExpiredJwtException e) {
            //过期了，返回false
            logger.debug("JWT token过期了");

            return false;
        } catch (Exception e) {
            logger.debug("{}", ExceptionUtil.stacktraceToString(e));
            return false;
        }
    }

    /**
     * 生成token
     *
     * @param user
     * @return
     */
    public static String generateToken(FUser user) {

        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USER_ID, user.getId());
        claims.put(CLAIM_KEY_USERNAME, user.getUsername());
        claims.put(CLAIM_KEY_PHONE, user.getPhone());
        claims.put(CLAIM_KEY_EMAIL, user.getEmail());
        //创建时间
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }
}
